/*******************************************************************************
 * Copyright (c) 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.internal.dnd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.IPerforceServerManager;
import net.sourceforge.perforce.core.resources.IP4File;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.TransferData;

/**
  * @version $Revision: 169 $
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class LocalFileTransfer extends ByteArrayTransfer 
{
	// --------------------------------------------------------------------------- Private Constants
	
	/** Stores the singleton instance. */
	private static final LocalFileTransfer INSTANCE = new LocalFileTransfer();
	
	/** Create a unique ID to make sure that different Eclipse applications use different "types" 
	  * of <code>ResourceTransfer</code>  
	  */
	private static final String TYPE_NAME = 
		"resource-transfer-format:" + System.currentTimeMillis() +                     //$NON-NLS-1$
		":" + INSTANCE.hashCode();                                                     //$NON-NLS-1$

	/** Stores the type id of the unique TYPE_NAME */
	private static final int TYPE_ID = registerType(TYPE_NAME);
	
	// ----------------------------------------------------------------------- Public Static Methods
	
	/** Call this method to retrieve the LocalFileTransfer singleton.
	  *
	  * @return the singleton instance 
	  */
	public static final LocalFileTransfer getInstance()
	{
		return INSTANCE;
	}
	
	// ------------------------------------------------------------------------ Private Constructors
	
	/** Constructor for LocalFileTransfer. */
	private LocalFileTransfer()
	{
	}
	
	// --------------------------------------------------------------------------- Protected Methods
	
	/** @see org.eclipse.swt.dnd.Transfer#getTypeIds() */
	protected int[] getTypeIds() 
	{
		return new int[] { TYPE_ID };
	}

	/** @see org.eclipse.swt.dnd.Transfer#getTypeNames() */
	protected String[] getTypeNames() 
	{
		return new String[] { TYPE_NAME };
	}
	
	/** @see ByteArrayTransfer#javaToNative(Object, TransferData) */
	protected void javaToNative(Object data, TransferData transferData) 
	{
		if (!(data instanceof IP4File[]))
		{
			return;
		}
		
		IP4File[] localFiles = (IP4File[]) data;
		
		ByteArrayOutputStream os = null;
		DataOutputStream dos = null;
		try
		{
			os = new ByteArrayOutputStream();
			dos = new DataOutputStream(os);
			
			dos.writeInt(localFiles.length);
			for (int i = 0; i < localFiles.length; i++)
			{
				writeLocalFile(dos, localFiles[i]);
			}
			
			super.javaToNative(os.toByteArray(), transferData);
		}
		catch (IOException e)
		{
			//it's best to send nothing if there were problems
		}
		finally
		{
			try 
			{
				if (dos != null)
				{
					dos.close();
				}
				
				if (os != null)
				{
					os.close();
				}
			} 
			catch (IOException e) 
			{
				// Ignored!
			}
		}		
	}
	
	/** @see ByteArrayTransfer#nativeToJava(TransferData) */
	protected Object nativeToJava(TransferData transferData) 
	{
		byte[] bytes = (byte[]) super.nativeToJava(transferData);
		if (bytes == null)
		{
			return new IP4File[0];
		}
		
		ByteArrayInputStream is = null;
		DataInputStream dis = null;
		try
		{
			is = new ByteArrayInputStream(bytes);
			dis = new DataInputStream(is);
			
			int count = dis.readInt();
			IP4File[] result = new IP4File[count];
			
			for (int i = 0; i < count; i++)
			{
				result[i] = readLocalFile(dis);
			}
			
			return result;
		}
		catch (IOException e)
		{
			//it's best to send nothing if there were problems
			return new IP4File[0];
		}
		finally
		{
			try 
			{
				if (dis != null)
				{
					dis.close();
				}
				
				if (is != null)
				{
					is.close();
				}
			} 
			catch (IOException e) 
			{
				// Ignored!
			}
		}
		
	}

	// ----------------------------------------------------------------------------- Private Methods

	/** Called to write the given LoaclFile to the specifed DataOutputStream.
	  *
	  * @param dos the DataOutputStream
	  * @param localFile the LocalFile instance.
	  * 
	  * @throws IOException in case of an I/O error.
	  */
	private void writeLocalFile(DataOutputStream dos, IP4File localFile) 
		throws IOException
	{
		dos.writeUTF(localFile.getServer().getUniqueName());
		dos.writeUTF(localFile.getLocation().toOSString());
	}

	/** Called to read LocalFile instances from the given DataInputStream.
	  * 
	  * @param dis the DataInputStream.
	  * @return the LocalFile instance that was read.
	  * @throws IOException in case of an I/O error
	  */
	private IP4File readLocalFile(DataInputStream dis)
		throws IOException 
	{
		String uniqueName = dis.readUTF();
		IPerforceServerManager manager = PerforceCorePlugin.getServerManager();
		final IPerforceServer server = manager.getPerforceServer(uniqueName);
		
		String absolutePath = dis.readUTF();
		final IPath location = new Path(absolutePath);

		return new IP4File() 
		{
			public Integer getChangelistId() 
			{
				return null;
			}

			public boolean isResolved() 
			{
				return false;
			}

			public boolean hasOurLock() 
			{
				return false;
			}

			public String getName() 
			{
				return null;
			}

			public String getDepotFilename() 
			{
				return null;
			}

			public IPath getLocation() 
			{
				return location;
			}

			public Integer getRevision() 
			{
				return null;
			}

			public String getAction() 
			{
				return null;
			}

			public String getClientName() 
			{
				return null;
			}

			public IPerforceServer getServer() 
			{
				return server;
			}
		};		
	}
}
